iT邦幫忙

2024 iThome 鐵人賽

DAY 8
0
Kubernetes

K8s 資料庫管理系統系列 第 8

day 8 k8s圖書館資料庫管理系統

  • 分享至 

  • xImage
  •  

今天是第八天我們可以寫一個k8s圖書館資料庫管理系統,以下是我的程式碼

1. 系統架構

  • Database: 使用 MySQL 或 PostgreSQL 作為資料庫。
  • Backend API: 使用 Node.js 或 Python(如 Flask、Django)實現後端 API,提供對圖書館書籍資料的增、刪、改、查功能。
  • Frontend: 可以使用 React、Vue.js 或 Angular 作為前端框架,提供使用者介面來瀏覽和管理圖書館書籍。
  • Kubernetes: 使用 Kubernetes 來進行容器管理和自動化部署。

2. 建立資料庫 (MySQL)

首先需要建立一個 MySQL 部署在 Kubernetes 上的環境。

MySQL Kubernetes 部署 YAML 檔案

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  replicas: 1
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: rootpassword
        - name: MYSQL_DATABASE
          value: library
        ports:
        - containerPort: 3306
          name: mysql
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim

---

apiVersion: v1
kind: Service
metadata:
  name: mysql
spec:
  ports:
  - port: 3306
  selector:
    app: mysql

PersistentVolume 和 PersistentVolumeClaim

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 1Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/mnt/data"

---

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
spec:
  resources:
    requests:
      storage: 1Gi
  accessModes:
    - ReadWriteOnce

3. 建立後端 API

後端可以使用 Node.js,通過 Express 框架建立一個 REST API,並與 MySQL 進行交互。

Node.js(Express)API 代碼示例

package.json

{
  "name": "library-api",
  "version": "1.0.0",
  "main": "index.js",
  "dependencies": {
    "express": "^4.17.1",
    "mysql2": "^2.1.0"
  }
}

app.js

const express = require('express');
const mysql = require('mysql2');
const app = express();
app.use(express.json());

const connection = mysql.createConnection({
  host: 'mysql',
  user: 'root',
  password: 'rootpassword',
  database: 'library'
});

app.get('/books', (req, res) => {
  connection.query('SELECT * FROM books', (err, results) => {
    if (err) throw err;
    res.json(results);
  });
});

app.post('/books', (req, res) => {
  const { title, author } = req.body;
  connection.query('INSERT INTO books (title, author) VALUES (?, ?)', [title, author], (err) => {
    if (err) throw err;
    res.send('Book added!');
  });
});

const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Library API running on port ${PORT}`);
});

Backend 部署 YAML 檔案

apiVersion: apps/v1
kind: Deployment
metadata:
  name: library-backend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: library-backend
  template:
    metadata:
      labels:
        app: library-backend
    spec:
      containers:
      - name: library-backend
        image: node:14
        command: ["npm", "start"]
        workingDir: /app
        ports:
        - containerPort: 3000
        volumeMounts:
        - name: app-source
          mountPath: /app
      volumes:
      - name: app-source
        configMap:
          name: library-backend-config

---

apiVersion: v1
kind: Service
metadata:
  name: library-backend
spec:
  selector:
    app: library-backend
  ports:
  - protocol: TCP
    port: 3000
    targetPort: 3000

4. 建立前端應用

可以使用 React 或 Vue.js 來實現前端,用戶可以通過這個介面來查找和管理書籍。

React 示例

App.js

import React, { useState, useEffect } from 'react';

function App() {
  const [books, setBooks] = useState([]);
  const [title, setTitle] = useState('');
  const [author, setAuthor] = useState('');

  useEffect(() => {
    fetch('/api/books')
      .then(response => response.json())
      .then(data => setBooks(data));
  }, []);

  const addBook = () => {
    fetch('/api/books', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ title, author })
    }).then(() => {
      setBooks([...books, { title, author }]);
    });
  };

  return (
    <div>
      <h1>Library System</h1>
      <input placeholder="Title" value={title} onChange={(e) => setTitle(e.target.value)} />
      <input placeholder="Author" value={author} onChange={(e) => setAuthor(e.target.value)} />
      <button onClick={addBook}>Add Book</button>
      <ul>
        {books.map(book => <li key={book.title}>{book.title} by {book.author}</li>)}
      </ul>
    </div>
  );
}

export default App;

前端部署 YAML 檔案

apiVersion: apps/v1
kind: Deployment
metadata:
  name: library-frontend
spec:
  replicas: 1
  selector:
    matchLabels:
      app: library-frontend
  template:
    metadata:
      labels:
        app: library-frontend
    spec:
      containers:
      - name: library-frontend
        image: nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - name: app-static
          mountPath: /usr/share/nginx/html
      volumes:
      - name: app-static
        configMap:
          name: library-frontend-config

---

apiVersion: v1
kind: Service
metadata:
  name: library-frontend
spec:
  selector:
    app: library-frontend
  ports:
  - protocol: TCP
    port: 80
    targetPort: 80

5. Kubernetes Ingress (可選)

如果需要外部訪問前端或 API,可以使用 Kubernetes Ingress 來管理外部流量。

6. 整合 Kubernetes 部署

可以使用 kubectl apply -f 命令來依次部署上述的 YAML 檔案:

kubectl apply -f mysql-deployment.yaml
kubectl apply -f backend-deployment.yaml
kubectl apply -f frontend-deployment.yaml

1. MySQL Kubernetes 部署配置

mysql-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: mysql
spec:
  replicas: 1  # 部署一個 MySQL 副本
  selector:
    matchLabels:
      app: mysql
  template:
    metadata:
      labels:
        app: mysql
    spec:
      containers:
      - name: mysql
        image: mysql:5.7  # 使用 MySQL 5.7 的 Docker 映像
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: rootpassword  # MySQL 的 root 使用者密碼
        - name: MYSQL_DATABASE
          value: library  # 預設建立一個名為 library 的資料庫
        ports:
        - containerPort: 3306  # MySQL 預設的連接埠
        volumeMounts:
        - name: mysql-persistent-storage
          mountPath: /var/lib/mysql  # 將持久存儲掛載到容器中的 /var/lib/mysql 路徑
      volumes:
      - name: mysql-persistent-storage
        persistentVolumeClaim:
          claimName: mysql-pv-claim  # 使用 PVC 來請求持久存儲
  • Deployment: Kubernetes 部署中的 Deployment 控制器確保應用程式的正確部署與管理。這裡我們只需要一個 MySQL 的副本(replicas: 1)。
  • 容器配置: 使用 MySQL 5.7 版本的 Docker 映像,並通過環境變數設置 MySQL 的 root 密碼以及預設的資料庫名稱。
  • 持久存儲: volumeMountsvolumes 允許 MySQL 使用持久化的存儲,即使容器崩潰或重啟,資料依然保留。

persistent-volume.yaml

apiVersion: v1
kind: PersistentVolume
metadata:
  name: mysql-pv
spec:
  capacity:
    storage: 1Gi  # 定義持久存儲空間為 1 GB
  accessModes:
    - ReadWriteOnce  # 允許單個節點讀寫
  hostPath:
    path: "/mnt/data"  # 在節點上保存資料的路徑
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: mysql-pv-claim
spec:
  resources:
    requests:
      storage: 1Gi  # 請求 1 GB 的存儲
  accessModes:
    - ReadWriteOnce  # 單個節點讀寫
  • PersistentVolume (PV): Kubernetes 中的 PV 是實體存儲資源的抽象化。這裡定義了 1GB 的存儲並將其掛載到 /mnt/data
  • PersistentVolumeClaim (PVC): PVC 是用來請求 PV 的接口,通過 PVC 來告訴 Kubernetes 我們需要的存儲容量和訪問模式。

2. 後端 API (Node.js)

app.js

const express = require('express');
const mysql = require('mysql2');
const app = express();
app.use(express.json());  // 允許應用解析 JSON 請求

// 建立與 MySQL 資料庫的連接
const connection = mysql.createConnection({
  host: 'mysql',
  user: 'root',
  password: 'rootpassword',
  database: 'library'
});

// 查詢所有書籍的路由
app.get('/books', (req, res) => {
  connection.query('SELECT * FROM books', (err, results) => {
    if (err) throw err;
    res.json(results);  // 回傳所有書籍資料
  });
});

// 新增書籍的路由
app.post('/books', (req, res) => {
  const { title, author } = req.body;
  connection.query('INSERT INTO books (title, author) VALUES (?, ?)', [title, author], (err) => {
    if (err) throw err;
    res.send('Book added!');  // 回應 "書籍已新增"
  });
});

// 後端 API 運行在 3000 埠
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
  console.log(`Library API running on port ${PORT}`);
});
  • Express 伺服器: 使用 Express 作為 Web 框架來建立後端 API。app.use(express.json()) 設定解析 JSON 的能力,允許 API 接收和處理 JSON 格式的資料。
  • MySQL 連接: 使用 mysql2 建立與 MySQL 的連接,並設定資料庫名稱和帳戶資訊。
  • GET /books 路由: 這個路由返回資料庫中所有書籍的清單。
  • POST /books 路由: 允許使用者新增書籍到資料庫中,並回應操作成功。

Kubernetes 後端部署配置

backend-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: library-backend
spec:
  replicas: 1  # 部署一個後端服務副本
  selector:
    matchLabels:
      app: library-backend
  template:
    metadata:
      labels:
        app: library-backend
    spec:
      containers:
      - name: library-backend
        image: node:14  # 使用 Node.js 14 的 Docker 映像
        command: ["npm", "start"]  # 啟動應用時執行 npm start
        workingDir: /app  # 應用的工作目錄
        ports:
        - containerPort: 3000  # 應用運行在 3000 埠
        volumeMounts:
        - name: app-source
          mountPath: /app  # 掛載應用程式的源代碼
      volumes:
      - name: app-source
        configMap:
          name: library-backend-config  # 從 ConfigMap 獲取應用的源代碼
  • Deployment: 部署了 Node.js 後端,容器內執行 npm start 命令來啟動應用。
  • Volume: 使用 ConfigMap 來掛載應用的源代碼,這樣可以動態更新應用。

3. 前端應用(React)

App.js

import React, { useState, useEffect } from 'react';

function App() {
  const [books, setBooks] = useState([]);  // 定義 state 來儲存書籍資料
  const [title, setTitle] = useState('');  // 用來輸入書名的 state
  const [author, setAuthor] = useState('');  // 用來輸入作者的 state

  // 使用 useEffect 在第一次渲染時抓取書籍資料
  useEffect(() => {
    fetch('/api/books')  // 從後端 API 抓取書籍資料
      .then(response => response.json())
      .then(data => setBooks(data));
  }, []);

  // 新增書籍
  const addBook = () => {
    fetch('/api/books', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ title, author })  // 送出新增的書籍資料
    }).then(() => {
      setBooks([...books, { title, author }]);  // 更新 state,添加新書
    });
  };

  return (
    <div>
      <h1>Library System</h1>
      <input placeholder="Title" value={title} onChange={(e) => setTitle(e.target.value)} />  {/* 書名輸入 */}
      <input placeholder="Author" value={author} onChange={(e) => setAuthor(e.target.value)} />  {/* 作者輸入 */}
      <button onClick={addBook}>Add Book</button>  {/* 新增書籍按鈕 */}
      <ul>
        {books.map(book => <li key={book.title}>{book.title} by {book.author}</li>)}  {/* 顯示書籍清單 */}
      </ul>
    </div>
  );
}

export default App;
  • React Hooks: useState 用於定義書籍清單和表單輸入的狀態,useEffect 在頁面載入時從 API 抓取書籍資料。
  • 表單處理: 書名和作者的輸入通過 onChange 事件處理,按下按鈕會將新書資料提交給後端 API。

Kubernetes 前端部署配置

frontend-deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: library-frontend
spec:
  replicas: 1  # 部署一個前端服務副本
  selector:
    matchLabels:
      app: library-frontend
  template:
    metadata:
      labels:
        app: library-frontend
    spec:
      containers:
      - name: library-frontend
        image: node:14  # 使用 Node.js 來執行前端應用
        command: ["npm", "start"]  # 使用 npm start 啟動 React 應用
        workingDir: /app
        ports:
        - containerPort: 3000
        volumeMounts:
        - name: app-source
          mountPath: /app
      volumes:
      - name: app-source
        configMap:
          name: library-frontend-config
  • 與後端部署類似,前端的部署配置會在 Kubernetes 中運行 React 應用。

這些文件展示了如何使用 Kubernetes 部署一個完整的應用程式,包括 MySQL 資料庫、Node.js 後端 API 和 React 前端應用。


上一篇
day 7 k8s的歷史
下一篇
Day 9 K8s公車資料庫管理系統
系列文
K8s 資料庫管理系統30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言